/* 
 * File:   PermutationGenome.cpp
 * Author: Chandra Kirchrath
 * 
 * Created on December 14, 2014, 4:06 PM
 */

#include <map>

#include "PermutationGenome.h"
#include "Genome.h"
#include "Util.h"
#include "IntGene.h"
#include "Gene.h"
#include "../TSPGenome.h"
namespace practical {
namespace ga {

PermutationGenome::PermutationGenome(): Genome() {}
PermutationGenome::PermutationGenome(const PermutationGenome& orig): Genome(orig) {}
PermutationGenome::PermutationGenome(const std::vector<IntGene>& genes): Genome(genes) {}
PermutationGenome::PermutationGenome(const Genome& other): Genome(other) {}

std::pair<Genome*, Genome*> PermutationGenome::crossover(const Genome& other) const {
	/**
	 * Die durch shallowCopy erzeugten instanzen werden entweder in die gene des
	 * Organismus aufgenommen und spaeter durch clearGenes geloescht oder wenn
	 * das Genome nicht verwendet wird gleich geloescht.
     */
	PermutationGenome* oneGenome = (PermutationGenome*) this->shallowCopy();
	PermutationGenome* twoGenome = (PermutationGenome*) this->shallowCopy();
	
	
	int l = genes.size();
	int cp = util::randInt(l);
	std::vector<IntGene> otherGenes = other.getGenes();

	std::map<IntGene, bool> usedOne;
	std::map<IntGene, bool> usedTwo;
	for (int i=0; i<cp; i++) {
		IntGene one = genes.at(i);
		usedOne[one] = true;
		oneGenome->genes.push_back(one);

		IntGene two = otherGenes.at(i);
		usedTwo[two] = true;
		twoGenome->genes.push_back(two);
	}

	// add remaining of 'other' into 'one'
	for (int i=0; i<l; i++) {
		IntGene gene = otherGenes.at(i);
		if (usedOne.count(gene) == 0) {
			oneGenome->genes.push_back(gene);
			usedOne[gene] = true;
		}
	}

	// add remaining of 'genes' into 'two'
	for (int i=0; i<l; i++) {
		IntGene gene = genes.at(i);
		if (usedTwo.count(gene) == 0) {
			twoGenome->genes.push_back(gene);
			usedTwo[gene] = true;
		}
	}

	std::pair<Genome*, Genome*> out(oneGenome, twoGenome);
	return out;
}

void PermutationGenome::mutate() {
	/**
	 * Amstatt einfach nur zwei zufallszahlen die auch gleich sein koennen muss
	 * auf den menge der moeglichen loesungen ein shuffle nach dem ersten
	 * treffer gemacht werden
     */
	int l = genes.size();
	int base [l];
	for (int i = 0; i < l; i++) {
		base[i] = i;
	}
	int one = util::randInt(l);
	l--;
	// aktuellen treffer ans ende verschieben
	base[one] = base[l];
	// zweite muss aus base da index nicht mehr wert entspricht
	int two = base[util::randInt(l)];

	IntGene oneG = genes.at(one);
	genes[one] = genes[two];
	genes[two] = oneG;
}
	
}
}

